﻿using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using VSIXUtilities.DataObjects;
using VSIXUtilities.DataObjects.Enums;

namespace CodeDocumentationSynchronizer.CodDocSync.EventsListeners
{
    class VsSelectionEvents : IVsSelectionEvents, IDisposable
    {
        #region Fields

        int intActive = 0;
        private IVsMonitorSelection monitorSelectionService = null;
        private uint pdwCookie;
        private readonly uint CookieSolutionExists;
        private readonly uint CookieSolutionHasSingleProject;
        private readonly uint CookieSolutionHasMultipleProjects;
        private readonly uint CookieBuilding;
        private readonly uint CookieDebugging;
        private readonly uint CookieDocSyncMain;
        private readonly uint CookieDocSyncSolutionExplorer;
        public bool SolutionExists
        {
            get;
            private set;
        }
        public bool SolutionHasSingleProject
        {
            get;
            private set;
        }
        public bool SolutionHasMultipleProjects
        {
            get;
            private set;
        }
        public bool Building
        {
            get;
            private set;
        }
        public bool Debugging
        {
            get;
            private set;
        }
        public bool DocSyncMain
        {
            get;
            private set;
        }
        public bool DocSyncSolutionExplorer
        {
            get;
            private set;
        }

        #endregion

        #region Constructors
        public VsSelectionEvents()
        {
            Guid GuidSolutionExists = VSConstants.UICONTEXT_SolutionExists;
            Guid GuidSolutionHasSingleProject = VSConstants.UICONTEXT_SolutionHasSingleProject;
            Guid GuidSolutionHasMultipleProjects = VSConstants.UICONTEXT_SolutionHasMultipleProjects;
            Guid GuidBuilding = VSConstants.UICONTEXT_SolutionBuilding;
            Guid GuidDebugging = VSConstants.UICONTEXT_Debugging;
            Guid GuidDocSyncMain = GuidList.UICONTEXT_DocSyncMain;
            Guid GuidDocSyncSolutionExplorer = GuidList.UICONTEXT_DocSyncSolutionExplorer;
            monitorSelectionService = ServiceProvider.GlobalProvider.GetService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
            if (monitorSelectionService != null)
            {
                monitorSelectionService.GetCmdUIContextCookie(ref GuidSolutionExists, out CookieSolutionExists);
                monitorSelectionService.GetCmdUIContextCookie(ref GuidSolutionHasSingleProject, out CookieSolutionHasSingleProject);
                monitorSelectionService.GetCmdUIContextCookie(ref GuidSolutionHasMultipleProjects, out CookieSolutionHasMultipleProjects);
                monitorSelectionService.GetCmdUIContextCookie(ref GuidBuilding, out CookieBuilding);
                monitorSelectionService.GetCmdUIContextCookie(ref GuidDebugging, out CookieDebugging);
                monitorSelectionService.GetCmdUIContextCookie(ref GuidDocSyncMain, out CookieDocSyncMain);
                monitorSelectionService.GetCmdUIContextCookie(ref GuidDocSyncSolutionExplorer, out CookieDocSyncSolutionExplorer);
                monitorSelectionService.AdviseSelectionEvents(this, out pdwCookie);
            }
        }
        #endregion

        #region Properties

        public IVsHierarchyWrapper CurrentlyOpened
        {
            get;
            private set;
        }
        public IVsHierarchyWrapper CurrentlySelected
        {
            get;
            private set;
        }
        public IVsHierarchyWrapper CurrentProject
        {
            get
            {
                return GetCurrentProject();
            }
        }
        public IVsHierarchyWrapper CurrentSolution
        {
            get
            {
                return GetCurrentSolution();
            }
        }
        #endregion

        #region IVsSelectionEvents Members

        int IVsSelectionEvents.OnCmdUIContextChanged(uint dwCmdUICookie, int fActive)
        {
            if (monitorSelectionService != null)
            {
                monitorSelectionService.IsCmdUIContextActive(CookieSolutionExists, out intActive);
                SolutionExists = Convert.ToBoolean(intActive);
                monitorSelectionService.IsCmdUIContextActive(CookieSolutionHasSingleProject, out intActive);
                SolutionHasSingleProject = Convert.ToBoolean(intActive);
                monitorSelectionService.IsCmdUIContextActive(CookieSolutionHasMultipleProjects, out intActive);
                SolutionHasMultipleProjects = Convert.ToBoolean(intActive);
                monitorSelectionService.IsCmdUIContextActive(CookieBuilding, out intActive);
                Building = Convert.ToBoolean(intActive);
                monitorSelectionService.IsCmdUIContextActive(CookieDebugging, out intActive);
                Debugging = Convert.ToBoolean(intActive);
                monitorSelectionService.IsCmdUIContextActive(CookieDocSyncMain, out intActive);
                DocSyncMain = Convert.ToBoolean(intActive);
                monitorSelectionService.IsCmdUIContextActive(CookieDocSyncSolutionExplorer, out intActive);
                DocSyncSolutionExplorer = Convert.ToBoolean(intActive);
            }
            return VSConstants.S_OK;
        }

        public int OnElementValueChanged(uint elementid, object varValueOld, object varValueNew)
        {
            if (elementid == (uint)VSConstants.VSSELELEMID.SEID_WindowFrame)
            {
                if (varValueNew == null)
                {
                    EnableDisableUICONTEXT_DocSyncMain(false);
                    CurrentlyOpened = null;
                }
                else
                {
                    IVsWindowFrameWrapper IVsWindowFrameWrapperInstance = new IVsWindowFrameWrapper((IVsWindowFrame)varValueNew);
                    EnableDisableUICONTEXT_DocSyncMain(IVsWindowFrameWrapperInstance.Type == IVsWindowFrameType.Document && IVsWindowFrameWrapperInstance.MkDocument.EndsWith(".cs"));
                    if (IVsWindowFrameWrapperInstance.Hierarchy == null || IVsWindowFrameWrapperInstance.ItemID == 0)
                    {
                        CurrentlyOpened = null;
                    }
                    else
                    {
                        CurrentlyOpened = new IVsHierarchyWrapper(IVsWindowFrameWrapperInstance.Hierarchy, (uint)IVsWindowFrameWrapperInstance.ItemID);
                    }
                }
            }
            return VSConstants.S_OK;
        }

        public int OnSelectionChanged(IVsHierarchy pHierOld, uint itemidOld, IVsMultiItemSelect pMISOld, ISelectionContainer pSCOld, IVsHierarchy pHierNew, uint itemidNew, IVsMultiItemSelect pMISNew, ISelectionContainer pSCNew)
        {
            if (pHierNew == null)//The solution node is selected
            {
                CurrentlySelected = null;
                EnableDisableUICONTEXT_DocSyncSolutionExplorer(true);
                return VSConstants.S_OK;
            }
            else
            {
                CurrentlySelected = new IVsHierarchyWrapper(pHierNew, itemidNew); ;
                if (CurrentlySelected.IsProject || (CurrentlySelected.IsProjectItem && CurrentlySelected.Name.ToLower().EndsWith(".cs")))
                {
                    EnableDisableUICONTEXT_DocSyncSolutionExplorer(true);
                    return VSConstants.S_OK;
                }
            }
            EnableDisableUICONTEXT_DocSyncSolutionExplorer(false);
            return VSConstants.S_OK;
        }

        #endregion

        private void EnableDisableUICONTEXT_DocSyncMain(bool Enabled)
        {
            monitorSelectionService.SetCmdUIContext(CookieDocSyncMain, Convert.ToInt16(Enabled && !Building && !Debugging && (SolutionHasSingleProject || SolutionHasMultipleProjects)));
        }

        private void EnableDisableUICONTEXT_DocSyncSolutionExplorer(bool Enabled)
        {
            monitorSelectionService.SetCmdUIContext(CookieDocSyncSolutionExplorer, Convert.ToInt16(Enabled && !Building && !Debugging && (SolutionHasSingleProject || SolutionHasMultipleProjects)));
        }

        private IVsHierarchyWrapper GetCurrentProject()
        {
            if (CurrentlyOpened == null && CurrentlySelected == null)
            {
                return null;
            }
            IVsHierarchyWrapper IVsHierarchyWrapperCurrent = (CurrentlyOpened == null) ? CurrentlySelected : CurrentlyOpened;
            if (IVsHierarchyWrapperCurrent.IsProject)
            {
                return IVsHierarchyWrapperCurrent;
            }
            else if (IVsHierarchyWrapperCurrent.IsRoot)
            {
                return null;
            }
            else
            {
                IVsHierarchyWrapper IVsHierarchyWrapperParent = IVsHierarchyWrapperCurrent.Parent;
                while (!IVsHierarchyWrapperParent.IsProject)
                {
                    IVsHierarchyWrapperParent = IVsHierarchyWrapperParent.Parent;
                }
                return IVsHierarchyWrapperParent;
            }
        }

        private IVsHierarchyWrapper GetCurrentSolution()
        {
            if (!SolutionExists)
            {
                return null;
            }
            IVsSolution solution = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution)) as IVsSolution;
            IVsHierarchy IVHSolution = (IVsHierarchy)solution;
            return new IVsHierarchyWrapper(IVHSolution, VSConstants.VSITEMID_ROOT);
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (monitorSelectionService != null && pdwCookie != 0)
            {
                monitorSelectionService.UnadviseSelectionEvents(pdwCookie);
            }
        }

        #endregion
    }
}
